package com.barbarossa.vod.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.scheme.SocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

public class WebUtils {

	public class Response {
		public String contentEncoding = null;
		public long contentLength = 0;
		public String contentType = null;
		public String message = null;
		public String errorReason = null;
		public int statusCode = 0;

		public Response() {
		}

		public Response(int statusCode, String contentType,
				String contentEncoding, long contentLength, String errorReason) {
			this.statusCode = statusCode;
			this.contentType = contentType;
			this.contentEncoding = contentEncoding;
			this.contentLength = contentLength;
			this.errorReason = errorReason;
		}

		public Response(String errorReason) {
			this.errorReason = errorReason;
		}

		public String getContentEncoding() {
			return contentEncoding;
		}

		public long getContentLength() {
			return contentLength;
		}

		public String getContentType() {
			return contentType;
		}

		public String getMessage() {
			return message;
		}

		public void setMessage(String message) {
			this.message = message;
		}

		public String getErrorReason() {
			return errorReason;
		}

		public int getStatusCode() {
			return statusCode;
		}

		public void setContentEncoding(String contentEncoding) {
			this.contentEncoding = contentEncoding;
		}

		public void setContentLength(long contentLength) {
			this.contentLength = contentLength;
		}

		public void setContentType(String contentType) {
			this.contentType = contentType;
		}

		public void setErrorReason(String errorReason) {
			this.errorReason = errorReason;
		}

		public void setStatusCode(int statusCode) {
			this.statusCode = statusCode;
		}

	}

	public static enum TYPE {
		GET, POST, PUT, DELETE
	}

	// private boolean GZIP = true;
	//
	private DefaultHttpClient client;
	private int networkPool = 4;
	private SocketFactory ssf;
	private int timeout = 30000;
	private String userAgent = null;
	private String referer = null;
	private int bufferSize = 1024;

	public String getUserAgent() {
		return userAgent;
	}

	public void setUserAgent(String userAgent) {
		this.userAgent = userAgent;
	}

	public String getReferer() {
		return referer;
	}

	public void setReferer(String referer) {
		this.referer = referer;
	}

	// {
	//
	// for(Map.Entry<String, Object> e: params.entrySet()){
	// value = e.getValue();
	// if(value != null){
	// pairs.add(new BasicNameValuePair(e.getKey(), value.toString()));
	// }
	// }

	public String combineUrl(String source, String relative) {
		System.out.println("source = " + source + "; relative = " + relative);

		if (isAbsoluteUrl(relative))
			return relative;

		return source + relative;
	}

	synchronized private DefaultHttpClient getClient() {

		if (client == null) {

			HttpParams httpParams = new BasicHttpParams();
			HttpConnectionParams.setConnectionTimeout(httpParams, timeout);
			HttpConnectionParams.setSoTimeout(httpParams, timeout);

			ConnManagerParams.setMaxConnectionsPerRoute(httpParams,
					new ConnPerRouteBean(networkPool));

			// Added this line to avoid issue at:
			// http://stackoverflow.com/questions/5358014/android-httpclient-oom-on-4g-lte-htc-thunderbolt
			HttpConnectionParams.setSocketBufferSize(httpParams, 8192);

			SchemeRegistry registry = new SchemeRegistry();
			registry.register(new Scheme("http", PlainSocketFactory
					.getSocketFactory(), 80));
			registry.register(new Scheme("https",
					ssf == null ? SSLSocketFactory.getSocketFactory() : ssf,
					443));

			ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(
					httpParams, registry);
			client = new DefaultHttpClient(cm, httpParams);
		}
		return client;
	}

	protected HttpUriRequest getRequest(String url, TYPE type) {
		switch (type) {
		case GET:
			return new HttpGet(url);
		case POST:
			return new HttpPost(url);
		case PUT:
			return new HttpPut(url);
		case DELETE:
			return new HttpDelete(url);
		default:
			return null;
		}
	}

	protected String makeCookie(Map<String, String> cookies) {

		if (cookies == null || cookies.size() == 0)
			return null;

		Iterator<String> iter = cookies.keySet().iterator();

		StringBuilder sb = new StringBuilder();

		while (iter.hasNext()) {
			String key = iter.next();
			String value = cookies.get(key);
			sb.append(key);
			sb.append("=");
			sb.append(value);
			if (iter.hasNext()) {
				sb.append("; ");
			}
		}

		return sb.toString();

	}

	public boolean isAbsoluteUrl(String url) {
		if ((url.startsWith("http://") || url.startsWith("https://")))
			return true;

		return false;
	}

	// protected HttpParams getHttpParam(HashMap<String, String> params) {
	// HttpParams httpParams = new BasicHttpParams();
	// return null;
	// }

	public Response requestWebpageText(String url, ByteArrayOutputStream output) {
		return requestWebpageResponse(url, TYPE.GET, null, null, null, output);
	}

	public Response requestWebFile(String url, FileOutputStream output) {
		return requestWebpageResponse(url, TYPE.GET, null, null, null, output);
	}

	protected Response requestWebpageResponse(String url, TYPE type,
			HashMap<String, String> headers, HashMap<String, Object> params,
			Map<String, String> cookies, OutputStream output) {

		HttpUriRequest httpRequest = getRequest(url, type);
		if (null == httpRequest)
			return new Response("invalid request type: " + type.toString());

		HttpClient httpclient = getClient();
		if (null != userAgent) {
			httpRequest.addHeader("User-Agent", userAgent);
		}

		if (null != headers) {
			for (String name : headers.keySet()) {
				httpRequest.addHeader(name, headers.get(name));
			}
		}

		String cookie = makeCookie(cookies);
//		String cookie = "path=/; domain=xunlei.com";
		if (cookie != null) {
			httpRequest.addHeader("Cookie", cookie);
		}
		
		if (null != referer) {
			httpRequest.setHeader("referer", referer);
		}

		HttpContext context = new BasicHttpContext();
		CookieStore cookieStore = new BasicCookieStore();
		context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);

		Response resp = null;
		try {
			HttpResponse response = httpclient.execute(httpRequest, context);
			resp = new Response();
			resp.setStatusCode(response.getStatusLine().getStatusCode());
			resp.setMessage(response.getStatusLine().getReasonPhrase());
			HttpEntity entity = response.getEntity();
			if (null != entity) {
				resp.setContentLength(entity.getContentLength());
				if (null != entity.getContentType())
					resp.setContentType(entity.getContentType().getValue());
				if (null != entity.getContentEncoding())
					resp.setContentEncoding(entity.getContentEncoding().getValue());
				if (resp.getStatusCode() < 200 || resp.getStatusCode() >= 300) {
					resp.setErrorReason(EntityUtils.toString(entity));
					return resp;
				}

				if (null == output)
					return resp;

				InputStream in = entity.getContent();
				if (null != in) {
					byte buffer[] = new byte[bufferSize];
					int read = 0;
					try {
						do {
							read = in.read(buffer, 0, buffer.length);
							if (read > 0) {
								output.write(buffer, 0, read);
							}
						} while (read >= 0);
						// output.write(EntityUtils.toByteArray(entity)); //equivalent
					} finally {
						in.close();
						output.flush();
					}
				}
			}
			return resp;

		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return new Response("ClientProtocolException");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return new Response("IOException");
		}
	}
	
	public String getWebpageText(String url) {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		Response resp = requestWebpageText(url, output);
		if (null == resp)
			return null;
		String html = output.toString();
		return html;		
	}

	public byte[] getWebpageBuffer(String url) {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		Response resp = requestWebpageText(url, output);
		if (null == resp)
			return null;
		byte[] ret = output.toByteArray();
		return ret;		
	}
	
	public boolean getDownloadedFile(String url, File f, String filename) {
		File saveFile = null;
		if (null == f)
			saveFile = new File(filename);
		else
			saveFile = f;
		FileOutputStream output = null;
		Response resp = null;
		
		try {
			output = new FileOutputStream(saveFile);
			resp = requestWebFile(url, output);
			output.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}

		if (null == resp)
			return false;
		
		if (resp.getStatusCode() < 200 || resp.getStatusCode() >= 300) {
			return false;
		}
		
		return true;
	}
	
	//
	//
	//
	// }else{
	//
	// HttpEntity entity = response.getEntity();
	//
	// HttpHost currentHost = (HttpHost)
	// context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
	// HttpUriRequest currentReq = (HttpUriRequest)
	// context.getAttribute(ExecutionContext.HTTP_REQUEST);
	// redirect = currentHost.toURI() + currentReq.getURI();
	//
	// int size = Math.max(32, Math.min(1024 * 64, (int)
	// entity.getContentLength()));
	//
	// PredefinedBAOS baos = new PredefinedBAOS(size);
	//
	// Header encoding = entity.getContentEncoding();
	// if(encoding != null && encoding.getValue().equalsIgnoreCase("gzip")) {
	// InputStream is = new GZIPInputStream(entity.getContent());
	// AQUtility.copy(is, baos);
	// }else{
	// entity.writeTo(baos);
	//
	// }

}
